package cn.jtfadmin.base.lang.common.utils;

import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;

public class AopUtils {

    /**
     * 获取被代理类的Object
     * @author Monkey
     */
    public static Object getTarget(Object proxy) {
        Object target = proxy;
        while (isProxy(target)){
            if(org.springframework.aop.support.AopUtils.isCglibProxy(target)) {
                target = getCglibProxyTargetObject(target);
            }
            if(org.springframework.aop.support.AopUtils.isJdkDynamicProxy(target)) {
                target = getJdkDynamicProxyTargetObject(target);
            } else if(Proxy.isProxyClass(proxy.getClass())){ //cglib
                target = getJdkDynamicProxyTargetObject(target);
            }
        }
        return target;

    }

    /**
     * 判断是否是代理类
     * @param object
     * @return
     */
    public static boolean isProxy(Object object){
        return isJdkProxy(object) || isSpringProxy(object);
    }

    /**
     * 是否是jdk代理
     * @param object
     * @return
     */
    public static boolean isJdkProxy(Object object){
        return Proxy.isProxyClass(object.getClass());
    }


    /**
     * 判断是否是spring 代理
     * @param object
     * @return
     */
    public static boolean isSpringProxy(Object object){
        return org.springframework.aop.support.AopUtils.isAopProxy(object);
    }

    /**
     * CGLIB方式被代理类的获取
     * @author Monkey
     *
     */
    private static Object getCglibProxyTargetObject(Object proxy) {
        try {
            Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
            h.setAccessible(true);
            Object dynamicAdvisedInterceptor = h.get(proxy);
            Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
            advised.setAccessible(true);
            Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
            return target;
        }catch (Exception e){
            throw new RuntimeException(e);
        }

    }

    /**
     * JDK动态代理方式被代理类的获取
     * @author Monkey
     *
     */
    private static Object getJdkDynamicProxyTargetObject(Object proxy) {
        try {
            Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
            h.setAccessible(true);
            AopProxy aopProxy = (AopProxy) h.get(proxy);
            Field advised = aopProxy.getClass().getDeclaredField("advised");
            advised.setAccessible(true);
            Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
            return target;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}
